package com.sjsu.aws.primitve.client.doublebarrier;

import java.lang.management.ManagementFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sjsu.aws.doublebarrier.DoubleBarrier;
import com.sjsu.aws.doublebarrier.DoubleBarrierServiceImpl;

/**
 * 
 * @author Pawar Deepali
 * 
 */
public class Barrier {
	private static final Log	LOG	     = LogFactory.getLog(Barrier.class);
	private Object	         sharedMutex	= new Object();
	private Integer	         participantCount;
	private String	         participantId;
	
	private static String	 barrierId	 = "b111";
	DoubleBarrier	         db	         = new DoubleBarrier();
	
	public Barrier(Integer participantCount, String participantId)
	        throws Exception {
		this.participantCount = participantCount;
		this.participantId = participantId;
		db.setBarrierId(barrierId);
		db.setParticipantId(participantId);
		db.setJobId(participantId);
		createWhenThereIsNoNode(db);
	}
	
	public boolean ensureAllParticipantsAreReady() throws Exception {
		
		// createWhenThereIsNoNode(PARTICIPANTS + "/" + name, null);
		System.out.println("here");
		
		while (true) {
			synchronized (sharedMutex) {
				db.setBarrierId(barrierId);
				DoubleBarrierServiceImpl doubleBarrierServiceImpl = new DoubleBarrierServiceImpl();
				int noOfChildren = doubleBarrierServiceImpl
				        .getNoOfBarrierPaticipants(db);
				if (noOfChildren == participantCount) {
					return true;
				} else {
					waitUntilThereIsEventNotificationFromZooKeeper();
				}
			}
		}
	}
	
	public void ensureAllParticipantsStartTheirJobs() throws Exception {
		while (true) {
			synchronized (sharedMutex) {
				db.setBarrierId(barrierId);
				DoubleBarrierServiceImpl doubleBarrierServiceImpl = new DoubleBarrierServiceImpl();
				int noOfChildren = doubleBarrierServiceImpl
				        .getNoOfBarrierPaticipants(db);
				if (noOfChildren == participantCount) {
					return;
				} else {
					waitUntilThereIsEventNotificationFromZooKeeper();
				}
			}
		}
	}
	
	public boolean leave() throws Exception {
		final int anyVersion = -1;
		DoubleBarrier db = new DoubleBarrier();
		db.setBarrierId(barrierId);
		db.setParticipantId(this.participantId);
		DoubleBarrierServiceImpl doubleBarrierServiceImpl = new DoubleBarrierServiceImpl();
		doubleBarrierServiceImpl.removeParticipantFromBarrier(db);
		while (true) {
			synchronized (sharedMutex) {
				int noOfChildren = doubleBarrierServiceImpl
				        .getNoOfBarrierPaticipants(db);
				
				if (noOfChildren == 0) {
					System.out.println("Children already left");
					return true;
				} else {
					waitUntilThereIsEventNotificationFromZooKeeper();
				}
			}
		}
	}
	
	private String uniqueId() {
		return ManagementFactory.getRuntimeMXBean().getName()
		        + Thread.currentThread().getId();
	}
	
	private void createWhenThereIsNoNode(DoubleBarrier db) throws Exception {
		DoubleBarrierServiceImpl doubleBarrierServiceImpl = new DoubleBarrierServiceImpl();
		doubleBarrierServiceImpl.addParticipantToBarrier(db);
	}
	
	// @Override
	// public void process(WatchedEvent event) {
	// wakeUpWatingThread();
	// }
	
	private void wakeUpWatingThread() {
		synchronized (sharedMutex) {
			sharedMutex.notify();
		}
	}
	
	private void waitUntilThereIsEventNotificationFromZooKeeper()
	        throws InterruptedException {
		sharedMutex.wait();
	}
}
